/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */

package io.iec.edp.caf.multicontext.analysis;

import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class StartupAnalysisBeanPostProcesser implements BeanPostProcessor, Ordered {
    private String moduleName;
    private Map<String, Long> start;
    private Map<String, Long> end;

    private final String RPC_SERVICE="io.iec.edp.caf.rpc.api.annotation.RpcService";
    private final String RPC_SERVICE_BUNDLE="io.iec.edp.caf.rpc.api.annotation.GspServiceBundle";
    private final String REST="io.iec.edp.caf.rest.RESTEndpoint";


    public StartupAnalysisBeanPostProcesser(String moduleName){
        this.moduleName = moduleName;
        start = new HashMap<>();
        end = new HashMap<>();
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        start.put(beanName, System.currentTimeMillis());
        return bean;
    }


    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        //bean init time
        end.put(beanName, System.currentTimeMillis());
        long time = initializationTime(beanName);
        StartupAnalysisLog.countBeanTime("it tooks, "+time+"ms, to initialize "+beanName+" bean(@"+bean.getClass().getTypeName()+")");
//        log.error("it tooks, {}ms, to initialize \"{}\" bean(@{}).", time, beanName, bean.getClass().getTypeName());

//        else if(((MethodMetadata)beanDefinition.getSource()).getReturnTypeName().equalsIgnoreCase("io.iec.edp.caf.rest.RESTEndpoint")){
//            StartupAnalysisLog.countRestBean(moduleName);
//        }else if(((MethodMetadata)beanDefinition.getSource()).getAnnotationAttributes("RpcService")!=null){
//            StartupAnalysisLog.countRpcBean(moduleName);
//        }
        //记录rest bean
        if(bean.getClass().getTypeName().equalsIgnoreCase(REST)){
            StartupAnalysisLog.countRestBean(moduleName,beanName, bean.getClass().getTypeName());
        }else{//记录rpc bean
            var annotations = bean.getClass().getAnnotations();

            if(Arrays.stream(annotations).anyMatch(x->{
                return x.getClass().getTypeName().equalsIgnoreCase(RPC_SERVICE)
                        && x.getClass().getTypeName().equalsIgnoreCase(RPC_SERVICE_BUNDLE);
            })==false){
                var inte = bean.getClass().getInterfaces();
                if(inte!=null && inte.length>0){
                    for(var i: inte){
                        var annotations2 = i.getAnnotations();

                        if(Arrays.stream(annotations).anyMatch(x-> {
                            return x.getClass().getTypeName().equalsIgnoreCase(RPC_SERVICE)
                                    || x.getClass().getTypeName().equalsIgnoreCase(RPC_SERVICE_BUNDLE);
                        })==true){
                            StartupAnalysisLog.countRpcBean(moduleName,beanName, bean.getClass().getTypeName());
                        }
                    }
                }

            }else{
                StartupAnalysisLog.countRpcBean(moduleName,beanName, bean.getClass().getTypeName());
            }
        }


        return bean;
    }

    // this method returns initialization time of the bean.
    private long initializationTime(String beanName) {
        return end.get(beanName) - start.get(beanName);
    }

    @Override
    public int getOrder() {
        return Integer.MAX_VALUE;
    }
}
